package org.oy.sealogger.ui;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.Vector;

import javax.swing.JPanel;
import javax.swing.RootPaneContainer;

import org.apache.log4j.Logger;
import org.oy.sealogger.common.Config;
import org.oy.sealogger.common.MessageQueue;
import org.oy.sealogger.common.Messages;
import org.oy.sealogger.logger.XMLLogReader;
import org.oy.sealogger.logger.XMLLogger;
import org.oy.sealogger.parser.CurrentState;
import org.oy.sealogger.route.GPSLocation;
import org.oy.sealogger.route.Route;
import org.oy.sealogger.route.WaypointData;
import org.xml.sax.SAXException;

import fileReader.demo.reader.Map;
import fileReader.demo.reader.MapLayer;
import fileReader.demo.reader.Simulator;

public class LoggerGraphics extends JPanel {
		
	/**
	 * Generated serial version uid
	 */
	private static final long serialVersionUID = 1L;
	
	private Logger log = Config.getLogger();
	
	private LoggerMenu menu = null;
	private ButtonPanel btnPanel = null;
	
	private Simulator simulator;
	private Screen screen;
	
	private Map map = null;

    //  RootPaneContainer interface 
    private RootPaneContainer rootPane = null;
    
    private Boat boat = null;
    private Compass compass = null;
    private Speed speed = null;
    private Depth depth = null;
    private Location location = null;
	private InfoBox infobox = null;
	private XMLLogger xmllogger = null;
    private XMLLogReader xmllogreader = null;
    private Vector<Route> routes = null;
    
	/**
	 * Constructor for the class LoggerGraphics.
	 *
	 */
	public LoggerGraphics() {
		this.initGraphics();
	}
	
	public void setFrame(Simulator frame) {
		this.simulator = frame;
		this.screen = new Screen(this.simulator);
		
		btnPanel = new ButtonPanel(this.simulator,this,xmllogger);
		menu = new LoggerMenu(this,this.simulator.getJMenuBar(), this);
	}
	
	public void setXMLLogger(XMLLogger xmllogger) {
		this.xmllogger = xmllogger;
	}
	
	//TODO
	protected boolean openLogFile(String filename) {
		boolean result = true;
		
		if (xmllogreader == null) {
			xmllogreader = new XMLLogReader();
		}
		if (routes == null) {
			routes = new Vector<Route>();
		}
		
		Route route = null;
		try {
			route = xmllogreader.readFile(filename);
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} catch (SAXException se) {
			se.printStackTrace();
		}
		
		if (route != null) {
			route.setVisible(true);
			routes.add(route);
			menu.reloadRouteMenu();
		} else {
			MessageQueue.getInstance().warning("Open File", Messages.getMessage("warning.cannot_open_log") + ": " + filename);
			result = false;
		}
		
		return result;
	}
	
	protected Vector<Route> getRoutes() {
		return routes;
	}

	public void setGlassPane(RootPaneContainer root) {
		rootPane = root;
		rootPane.setGlassPane(this);
		setOpaque(false);
		setVisible(true);
	}
	
	private void initGraphics() {
		compass = new Compass(this);
		boat = new Boat(this,false);
		speed = new Speed(this);
		depth = new Depth();
		location = new Location(this);
		infobox = new InfoBox(this);
	}
	
	private void drawGraphics(Graphics g) {
		if (menu.isShowSpeed()) {
			if (menu.isShowDepth()) {
				speed.draw(g,this.screen.getXCoordinate(2),this.screen.getYCoordinate(2),
						this.screen.getItemWidth(2),this.screen.getSmallItemHeight());
			} else {
				speed.draw(g,this.screen.getXCoordinate(2),this.screen.getYCoordinate(3),
						this.screen.getItemWidth(2),this.screen.getSmallItemHeight());
			}

		}
		if (menu.isShowDepth()) {
			depth.draw(g,this.screen.getXCoordinate(3),this.screen.getYCoordinate(3),
					this.screen.getItemWidth(3),this.screen.getSmallItemHeight());
		}
		if (menu.isShowLocation()) {
			location.draw(g,this.screen.getXCoordinate(4),this.screen.getYCoordinate(4),
					this.screen.getItemWidth(4),this.screen.getSmallItemHeight());
			
		}
		if (menu.isShowInfo()) {
			infobox.draw(g,this.screen.getXCoordinate(5),this.screen.getYCoordinate(5),
					this.screen.getItemWidth(5),this.screen.getSmallItemHeight());

		}	
		if (menu.isShowButtons()) {
			this.btnPanel.showButtons();			
		} else {
			this.btnPanel.hideButtons();
		}
		
		drawRoutes(g);

		
		if (menu.isShowBoat()) {
    		boat.draw(g,getFrameWidth(),getFrameHeight(),this.screen.getBoatWidth(),this.screen.getBoatHeight(),
    				this.screen.getBoatYCoordSpace());
		}
		if (menu.isShowCompass()) {
			compass.draw(g,this.screen.getXCoordinate(1),this.screen.getYCoordinate(1),
						this.screen.getItemWidth(1),this.screen.getItemHeight());
		}
	}
	
	private void drawRoutes(Graphics g) {
		Graphics2D g2 = (Graphics2D)g;
		
		if (routes == null || map == null)
			return;
		
		for (int i = 0; i < routes.size(); i++) {

			Route currentRoute = routes.elementAt(i);
			Vector<GPSLocation> location = currentRoute.getPath();

			double lastx = 0;
			double lasty = 0;
			
			Point2D start = null;
			Point2D end = null;

			if(!currentRoute.isVisible())
				continue;
			
			for (int j = 0; j < location.size(); j++) {
				GPSLocation loc = location.elementAt(j);
				double lon = loc.getLongitude();
				double lat = loc.getLatitude();
				
				double a,b; // xy-pixels on screen
				
				double minX=MapLayer.getGlobalMin_x();
				double maxX=MapLayer.getGlobalMax_x();
				double minY=MapLayer.getGlobalMin_y();
				double maxY=MapLayer.getGlobalMax_y();
				
				//scalex and scaley has to be the same for all the layers to get right proportions
				//scalex and scaley makes the map fit the screen
				double scalex = 1600.0/(maxX-minX);	//adapt this to your screen
				double scaley = 900.0/(minY-maxY);	//adapt this to your screen
				
				double zoom = this.map.getZoom();
				double xtrans = this.map.getX_translation();
				double ytrans = this.map.getY_translation();
				
				a = ((lon - minX)*(scalex))*zoom+xtrans;
				b = ((lat - minY)*(scaley)+900)*zoom+ytrans;
				
				b += this.screen.getBoatYCoordSpace();
				b += (this.screen.getBoatWidth() / 2);
				
				end = new Point2D.Double(a,b);
				
				if (lastx == 0 && lasty == 0) {
					lastx = a;
					lasty = b;
					start = new Point2D.Double(lastx,lasty);
				} else {
					g2.setPaint(currentRoute.getColor());
					g2.setStroke(new BasicStroke(4));
					g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
					
					g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
					
					// drawing the waypoint
					/*if (loc instanceof WaypointData) {
						Ellipse2D waypoint = new Ellipse2D.Double(a, b, 10, 10);
						g2.draw(waypoint);
					}*/
					
					Line2D routeLine = new Line2D.Double(start,end);
					g2.draw(routeLine);
					
					
					start = end;
				}	
			}
		}
	}
	
	/**
	 * Returns Simulator frame height
	 * 
	 * @return simulator.getSize().height
	 */
	private int getFrameHeight() {
		return simulator.getSize().height;
	}
	
    public void paint(Graphics g) { 
    	super.paint(g);
    	
    	drawGraphics(g);
    }
	
	/**
	 * Returns Simulator frame width
	 * 
	 * @return simulator.getSize().width
	 */
	private int getFrameWidth() {
		return simulator.getSize().width;
	}
	
	public void startObserving(CurrentState state) {
		state.addObserver(speed);
		state.addObserver(location);
		state.addObserver(compass);
		state.addObserver(boat);

		MessageQueue.getInstance().addObserver(infobox);
	}
	
	//FIXME - metodi lisätty
	public Map getMap() {
		this.map = simulator.getMap();
		
		return this.map;
	}
	
	//FIXME - metodi lisätty
	public boolean isBoatAutoCenterON() {
		return this.btnPanel.getCenterMode();
	}
}
